package com.sm2cppa.utils;

import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.*;

import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

@Component
public class CertUtils {
    private final PublicKey publicKeyCA;
    private final PrivateKey privateKeyCA;

    public CertUtils()throws Exception {
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
        // 读取CA私钥
        InputStream skinputStream = getClass().getResourceAsStream("/account/gm/0x4c26aecee34487d29adff978fd6791578ed8fd28.pem");
         PEMParser pemParsersk = new PEMParser(new InputStreamReader(skinputStream));
        Object objectsk = pemParsersk.readObject();
        privateKeyCA = converter.getPrivateKey((PrivateKeyInfo) objectsk);
        pemParsersk.close();
        // 读取CA公钥
        InputStream pkinputStream = getClass().getResourceAsStream("/account/gm/0x4c26aecee34487d29adff978fd6791578ed8fd28.pem.pub");
        PEMParser pemParserpk=new PEMParser(new InputStreamReader(pkinputStream));
        Object objectpk = pemParserpk.readObject();
        publicKeyCA = converter.getPublicKey((SubjectPublicKeyInfo) objectpk);
        pemParserpk.close();
    }

    /**
     * 用CA的私钥签名生成公钥证书，并使用DER编码证书后转换为十六进制字符串返回
     * @param publicKeyBytes  SM2公钥
     * @return 十六进制字符串类型的公钥证书
     */
    public String makeCert(byte[] publicKeyBytes ) throws Exception{
//        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

        // 证书信息
        // 发行者issuer
        X500Name issuer = new X500Name("CN=Issuer, O=My Organization");
        // 主体subject
        X500Name subject = new X500Name("CN=Subject, O=My Organization");
        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
        Date notBefore = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
        Date notAfter = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000L);


        // 构建算法标识符，使用 SM2 OID
        ASN1ObjectIdentifier sm2Oid = new ASN1ObjectIdentifier(GMObjectIdentifiers.sm2p256v1.toString()); // SM2 OID
        AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(sm2Oid);

        // 创建 SubjectPublicKeyInfo
        ASN1BitString keyData = new DERBitString(publicKeyBytes);
        SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(
                algorithmIdentifier,
                keyData
        );


        // 创建证书构建器
        X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(
                issuer,
                serial,
                notBefore,
                notAfter,
                subject,
                subjectPublicKeyInfo
        );


        // 创建内容签名者
        ContentSigner contentSigner = new JcaContentSignerBuilder("SM3WITHSM2")
                .build(privateKeyCA);

        // 生成证书
        X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certificateBuilder.build(contentSigner));

        //DER编码的字节流转十六进制字符串
        return Hex.toHexString(certificate.getEncoded());
    }

    //pkCert="0x..."
    public  X509Certificate certRecoverfromtx(String pkCert)throws Exception{
        byte[] encodeCert= Hex.decode(pkCert.substring(2));
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        X509Certificate certificateRecover = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(encodeCert));
        return certificateRecover;
    }

    /**
     * 将DER编码的公钥证书恢复回证书
     * @param pkCert  DER编码的公钥证书
     * @return X509Certificate类型的公钥证书
     */
    public  X509Certificate certRecover(String pkCert)throws Exception{
        byte[] encodeCert= Hex.decode(pkCert);
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        X509Certificate certificateRecover = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(encodeCert));
        return certificateRecover;
    }

    public String pkRecover(String pkCert)throws Exception{
        X509Certificate cert=certRecover(pkCert);
        return cert2Pk(cert);
    }


    /**
     * 提取证书里的公钥，并将其格式化为十六进制的字符串形式
     * @param cert  公钥证书
     * @return 十六进制字符串形式的SM2公钥
     */
    public static String cert2Pk(X509Certificate cert) {
        PublicKey publicKey=cert.getPublicKey();
        byte[] encodedKey = publicKey.getEncoded();
        int headerLength = 19;
        byte[] keyBits = new byte[encodedKey.length - headerLength];
        System.arraycopy(encodedKey, headerLength, keyBits, 0, keyBits.length);
        // 返回unparsed keybits部分
        return Hex.toHexString(keyBits);
    }

    /**
     * 用CA的公钥验证证书
     * @param cert  证书
     * @return “验证通过”，若验证失败会抛出异常
     */
    public String CertVerify(X509Certificate cert)throws Exception {
        cert.verify(publicKeyCA, "BC");
        return "验证通过";

    }




}
